/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package es.unavarra.mti.iws.logic;

import es.unavarra.mti.iws.Manager;
import es.unavarra.mti.iws.gui.MainFrame;
import es.unavarra.mti.iws.gui.RenderPanel;
import es.unavarra.mti.iws.logic.editor.DefaultEditor;
import es.unavarra.mti.iws.logic.editor.KeyboardEvent;
import es.unavarra.mti.iws.logic.editor.Selectable;
import es.unavarra.mti.iws.logic.editor.TouchEvent;
import es.unavarra.mti.iws.model.Event;
import es.unavarra.mti.iws.model.Fire;
import es.unavarra.mti.iws.model.Link;
import es.unavarra.mti.iws.model.Model;
import es.unavarra.mti.iws.model.Node;
import es.unavarra.mti.iws.model.Quake;
import es.unavarra.mti.iws.model.Rain;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.locks.LockSupport;
import javax.imageio.ImageIO;

/**
 *
 * @author Asier
 */
public class LogicRunner extends Thread {
    public static final int STATUS_IDLE = 0;
    public static final int STATUS_INSERTING = 1;
    public static final int STATUS_SELECTING1 = 2;
    public static final int STATUS_SELECTING2 = 3;

    public static final int FPS = 30;

    private float mouseX,mouseY;

    private long lastNanos,sleepNanos;
    private boolean stoped,running,step;
    private Manager manager;
    private RenderPanel panel;
    private DefaultEditor editor;
    private int currentStatus;

    private BufferedImage imote, imoteSelected;
    private BufferedImage iris, irisSelected;
    private BufferedImage background;
    private BufferedImage fireIcon, rainIcon, quakeIcon;

    private Selectable inserting;
    private Node lastSelected;

    public LogicRunner(Manager manager) {
        this.manager = manager;
        panel = manager.getPanel();
        mouseX = panel.getWidth() / 2.0f;
        mouseY = panel.getHeight() / 2.0f;
        currentStatus = STATUS_IDLE;
        editor = new DefaultEditor(manager);
        loadImages();
    }

    private void loadImages() {
        String path = "/es/unavarra/mti/iws/resources/";
        try {
            imote = ImageIO.read(getClass().getResource(path + "imote.png"));
            imoteSelected = ImageIO.read(getClass().getResource(path + "imoteSelected.png"));
            iris = ImageIO.read(getClass().getResource(path + "iris.png"));
            irisSelected = ImageIO.read(getClass().getResource(path + "irisSelected.png"));
            background = ImageIO.read(getClass().getResource(path + "forestBackground.jpg"));
            fireIcon = ImageIO.read(getClass().getResource(path + "fireIcon.png"));
            rainIcon = ImageIO.read(getClass().getResource(path + "rainIcon.png"));
            quakeIcon = ImageIO.read(getClass().getResource(path + "quakeIcon.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void run() {
        while(!stoped){
            try{
                lastNanos = System.nanoTime();
                if(running || step){
                    doRun();
                    step = false;
                }else{
                    synchronized(this) {
                        try { wait();} catch (InterruptedException ex) {}
                    }
                }
                sleepNanos = Math.round( (1000000000.0/FPS) - (System.nanoTime() - lastNanos) );
                if(sleepNanos > 0){
                    LockSupport.parkNanos(sleepNanos);
                }else{
                    yield();
                }
            }catch(Exception ex){
                MainFrame.getInstance().error("Logicrunner " + ex.toString());
                ex.printStackTrace();
                pause();
            }
        }

    }

    public void pause(){
        running = false;
    }

    public void play(){
        running = true;
        synchronized(this){
            this.notifyAll();
        }
    }

    public void end() {
        stoped = true;
        try { interrupt(); }catch(Exception e){}
    }

    public void setInserting(Selectable inserting) {
        this.inserting = inserting;
        if((inserting instanceof Node) || (inserting instanceof Event)){
            currentStatus = STATUS_INSERTING;
        }else if(inserting instanceof Link){
            currentStatus = STATUS_SELECTING1;
        }
    }

    private void doRun() {
        Model model = manager.getModel();

        synchronized(panel.getGraphicLock()){
            //paint background
            panel.drawImage(background, background.getWidth()/2.0f, background.getHeight()/2.0f);

            if(model != null){
                synchronized(model){
                    for(Link l : model.getLinks()){
                            panel.line(l.getNodeSource().getX(), l.getNodeSource().getY(),
                                       l.getNodeTarget().getX(), l.getNodeTarget().getY(),
                                       editor.isInSelection(l)&&currentStatus==STATUS_IDLE?0xFFFFFFFF:0xFF0000FF);
                    }

                    for(Event e : model.getEvents()){
                        int color = 0xFF000000;
                        if( editor.isInSelection(e) &&currentStatus==STATUS_IDLE) { color = 0xA0FFFFFF;}
                        else if(e instanceof Fire) { color = 0x7FFF0000;}
                        else if (e instanceof Rain) { color = 0x7F0000FF; }
                        else if (e instanceof Quake) { color = 0x7F00FF00; }
                        panel.circleFill(e.getX(), e.getY(), e.getRadious(), color);
                    }

                    for(Node n : model.getNodes()){
                        BufferedImage toUse = fireIcon;
                        if (n.getType() == Node.TYPE_IMOTE){
                            if (editor.isInSelection(n) &&currentStatus==STATUS_IDLE){
                                toUse = imoteSelected;
                            }else{
                                toUse = imote;
                            }
                        }else if(n.getType() == Node.TYPE_IRIS){
                            if (editor.isInSelection(n) &&currentStatus==STATUS_IDLE){
                                toUse = irisSelected;
                            }else{
                                toUse = iris;
                            }
                        }
                        if(currentStatus == STATUS_SELECTING1 || currentStatus == STATUS_SELECTING2){
                            panel.drawImageColored(toUse, n.getX(), n.getY(),0x7FFFFFFF);
                        }else{
                            panel.drawImage(toUse, n.getX(), n.getY());
                        }
                        if (n.isHasFire()) { panel.drawImage(fireIcon, n.getX()-20, n.getY()-20); }
                        if (n.isHasRain()) { panel.drawImage(rainIcon, n.getX()+20, n.getY()-20); }
                        if (n.isHasQuake()) { panel.drawImage(quakeIcon, n.getX()+10, n.getY()+10); }
                    }
                }
            }

            if(currentStatus == STATUS_IDLE){
                if(model != null){
                    synchronized(model){
                        ArrayList<Selectable> all = new ArrayList<Selectable>(model.getNodes().size() +
                                model.getLinks().size() +
                                model.getEvents().size());
                        all.addAll(model.getEvents());
                        all.addAll(model.getLinks());
                        all.addAll(model.getNodes());
                        editor.tick(all);
                    }
                }
            }else if (currentStatus == STATUS_INSERTING){
                if (escPressed()) { resetStatus();return;}
                if(updateMousePosition()){
                    inserting.setPosition(mouseX, mouseY);
                    manager.getModel().addEntry(inserting);
                    resetStatus();
                    return;
                }
                drawSelectable(inserting,mouseX,mouseY);
            }else if (currentStatus == STATUS_SELECTING1){
                if (escPressed()) { resetStatus();return;}
                if(updateMousePosition()){
                    Node n = getNodeAt(mouseX, mouseY);
                    if (n != null){
                        currentStatus = STATUS_SELECTING2;
                        lastSelected = n;
                    }
                }
                Node n = getNodeAt(mouseX, mouseY);
                if (n != null) {
                    drawSelectable(n,n.getX(),n.getY());
                }

            }else if (currentStatus == STATUS_SELECTING2){
                if (escPressed()) { resetStatus(); return;}
                if(updateMousePosition()){
                    Node n = getNodeAt(mouseX, mouseY);
                    if (n != null){
                        Link l = (Link)inserting;
                        l.setNodeSource(lastSelected);
                        l.setNodeTarget(n);
                        model.addEntry(l);
                        resetStatus();
                        return;
                    }
                }
                panel.line(lastSelected.getX(), lastSelected.getY(), mouseX, mouseY, 0xFFFFFF00);
                Node n = getNodeAt(mouseX, mouseY);
                if (n != null) {
                    drawSelectable(n,n.getX(),n.getY());
                }
            }
            panel.repaint();
        }
    }

    private void resetStatus() {
        inserting = null;
        currentStatus = STATUS_IDLE;
        mouseX = panel.getWidth() / 2.0f;
        mouseY = panel.getHeight() / 2.0f;
        panel.repaint();
    }

    private Node getNodeAt(float x, float y){
        Node forReturn = null;
        ArrayList<Node> nodes = manager.getModel().getNodes();
        if(nodes == null) { return null; }
        synchronized(nodes){
            for(Node n : nodes){
                if (DefaultEditor.pointInsideSelectable(n, x, y)){
                    return n;
                }
            }
        }
        return forReturn;
    }

    private void drawSelectable(Selectable s,float x, float y){
        if(s instanceof Node){
            Node n = (Node)s;
            BufferedImage toUse = fireIcon;
            if (n.getType() == Node.TYPE_IMOTE) {
                if (editor.isInSelection(n) && currentStatus == STATUS_IDLE) {
                    toUse = imoteSelected;
                } else {
                    toUse = imote;
                }
            } else if (n.getType() == Node.TYPE_IRIS) {
                if (editor.isInSelection(n) && currentStatus == STATUS_IDLE) {
                    toUse = irisSelected;
                } else {
                    toUse = iris;
                }
            }
            panel.drawImageColored(toUse, x, y, 0xA0FFFFFF);
        }else if (s instanceof Event){
            Event e = (Event)s;
            panel.circleFill(x, y, e.getRadious(), 0xA0FFFFFF);
        }
    }

    private boolean escPressed(){
        KeyboardEvent t = null;
        while ((t = manager.getKeyEvent()) != null) {
            if (t.type == KeyboardEvent.TYPE_UP) {
                 if (t.keyCode == KeyEvent.VK_ESCAPE){
                     return true;
                 }
            }
        }
        return false;
    }

    private boolean updateMousePosition(){
        TouchEvent t = null;
        while ((t = manager.getTouchEvent()) != null) {
            if (t.n == 0) {
                 mouseX = t.x;
                 mouseY = t.y;
                 if (t.type == TouchEvent.TYPE_DOWN){
                    return true;
                 }
            }
        }
        return false;
    }

    public DefaultEditor getEditor() {
        return editor;
    }

    
}
